#ifndef _sbrush_dag_sms_synth_h_
#define _sbrush_dag_sms_synth_h_

#include "dag.h"
#include "dag_threading.h"
#include "sbrush_instrument_synthesizer.h"
#include "sms.h"
#include "sbrush_sms_synthesizer.h"

#include <memory>

namespace sbrush {
	
	/* TODO: move this class somewhere else */
	template <class _buffer_t>
	class DoubleBuffer {
	public:
		DoubleBuffer() 
		:	m_Order(true)
		{
		}
		~DoubleBuffer() throw() {
		}
		
		const _buffer_t& read() const {
			if (m_Order) {
				return m_Buffer1;
			}
			else {
				return m_Buffer2;
			}
		}
		
		_buffer_t& write() {
			if (m_Order) {
				return m_Buffer2;
			}
			else {
				return m_Buffer1;
			}
		}
		
		void swap() {
			m_Order = !m_Order;
		}
		
		const _buffer_t& buffer1() const {
			return m_Buffer1;
		}
		
		_buffer_t& buffer1() {
			return m_Buffer1;
		}
		
		const _buffer_t& buffer2() const {
			return m_Buffer2;
		}
		
		_buffer_t& buffer2() {
			return m_Buffer2;
		}
		
	private:
		bool m_Order;
		_buffer_t m_Buffer1;
		_buffer_t m_Buffer2;
	};
	
	
	class DagSmsSynth : public InstrumentSynthesizer,
						public dag::Runnable
	{
	public:
		DagSmsSynth();
		virtual ~DagSmsSynth() throw();
		void init(const SMS_Header& header,
				  std::auto_ptr<dag::FrameOperator> frameOp);
		void addAudio(float** buffer, 
					  size_t numFrames, 
					  size_t numChannels);
		void instrumentCallback(const Instrument* instrument,
								const InstrumentState& state);
		void runThread();
		
	private:
		void startProcessing();
		void stopProcessing();
		dag::Condition m_NewStateCondition;
		dag::Mutex m_ProcStateMutex;
		dag::Mutex m_SmsBufferMutex;
		bool m_IsRunning;
		volatile bool m_KeepRunning;
		
		std::auto_ptr<dag::FrameOperator> m_FrameOp;
		DoubleBuffer<InstrumentState> m_InstrumentStateBuffer;
		DoubleBuffer<SMS_Data> m_SmsBuffer;
		SmsSynthesizer m_SmsSynthesizer;
	};
}

#endif